home *** CD-ROM | disk | FTP | other *** search
- ;;;-*- mode:lisp;syntax :zetalisp; package: Boxer; fonts: cptfont, cptfontb -*-
-
- #|
- Copyright 1985 Massachusetts Institute of Technology
-
- Permission to use, copy, modify, distribute, and sell this software
- and its documentation for any purpose is hereby granted without fee,
- provided that the above copyright notice appear in all copies and that
- both that copyright notice and this permission notice appear in
- supporting documentation, and that the name of M.I.T. not be used in
- advertising or publicity pertaining to distribution of the software
- without specific, written prior permission. M.I.T. makes no
- representations about the suitability of this software for any
- purpose. It is provided "as is" without express or implied warranty.
-
-
- +-Data--+
- This file is part of the | BOXER | system
- +-------+
-
- This file defines the internal representation for Boxes used by the Evaluator.
- We use a different represention for boxes in the Evaluator for the following reasons:
-
- The Evaluator will have to create a large number of Boxes during the course
- of a normal execution. It is to our advantage to have small objects for boxes
- for both speed (CONSing time) and space considerations. General purpose Boxes
- are not small and they contain a lot of irrelevant(to the Evaluator) information.
-
- Having a different representation for Boxes also allows us to keep the format of
- the Box in a form that is partially pre-digested for the Evaluator--saving us
- a few more cycles.
-
- The Evaluator representation of a Box is known as an Evbox for Evaluator Box.
- Evboxes have the following properties:
-
- Its contents. The representation of the contents should be in a form that the
- Evaluator can deal with easily(what the reader spits out perhaps). Spacing information
- is also preserved.
-
- EvPORTS will have a pointer to the target of the port
-
- The name ?
-
- The Local Variable Bindings;
-
- This code is descended from similiar "Pre-box" code written by Mike Eisenberg
-
- The Actual Definitions for the structures used here are in the file EVDEFS
- |#
-
-
-
-
- ;;;; Some predicates
-
- (DEFUN BLANK-EV-ROW? (EV-ROW)
- (OR (NULL EV-ROW)
- (NOT (DOLIST (ENTRY EV-ROW) (UNLESS (SPACES? ENTRY) (RETURN T))))))
-
- (DEFUN EMPTY-EVROW? (EVROW)
- (OR (NULL EVROW) (NULL (EVROW-ENTRIES EVROW))))
-
- (DEFF BLANK-EV-ROW? #'EMPTY-EVROW?)
- (COMPILER:MAKE-OBSOLETE BLANK-EV-ROW? "Use EMPTY-EVROW? instead.")
-
- (DEFUN EMPTY-EVBOX? (EVBOX)
- (LET ((ROWS (EVBOX-ROWS EVBOX)))
- (OR (NULL ROWS)
- (NOT (DOLIST (ROW ROWS) (UNLESS (EMPTY-EVROW? ROW) (RETURN T)))))))
-
-
-
- ;;; HOW to translate Boxes (EDITOR instances) into evaluator objects (EvBoxes) and vice versa
-
- ;; make an empty EvBOX
- (DEFUN MAKE-EMPTY-EVBOX (&OPTIONAL (TYPE 'DATA-BOX))
- (SELECTQ TYPE
- ((DATA-BOX :DATA-BOX) (MAKE-EVDATA ROWS `(,(MAKE-EVROW))))
- ((DOIT-BOX :DOIT-BOX) (MAKE-EVDOIT ROWS `(,(MAKE-EVROW))))
- ((PORT-BOX :PORT-BOX) (MAKE-EVPORT)) ;will we EVER need to do this ???
- (OTHERWISE (FERROR "Don't know how to make an empty EvBox of type ~A" TYPE))))
-
- (DEFUN MAKE-EVROW-FROM-ROW (ROW)
- (MAKE-EVROW ENTRIES (TELL ROW :ENTRIES) ITEMS (TELL ROW :ITEMS)))
-
- (DEFUN MAKE-EVROWS-FROM-BOX (BOX)
- (MAPCAR #'MAKE-EVROW-FROM-ROW (TELL BOX :ROWS)))
-
- ;; need to flatten out exports here
- (defun copy-local-bindings (box)
- (let ((exporting-marker-entry (assq *exporting-box-marker*
- (TELL BOX :GET-STATIC-VARIABLES-ALIST))))
- (if (null exporting-marker-entry)
- (COPYLIST (TELL BOX :GET-STATIC-VARIABLES-ALIST))
- (nconc (remq exporting-marker-entry (TELL BOX :GET-STATIC-VARIABLES-ALIST))
- (copy-local-bindings (cdr exporting-marker-entry))))))
-
- (DEFUN GET-NAME-FOR-EVBOX (BOX)
- (IF (STRING-EQUAL (TELL BOX :NAME) "Un-named") NIL (TELL BOX :NAME)))
-
- ;;; Shallow copying for the evaluator
-
- (DEFUN COPY-EVBOX (EVBOX)
- "Does a top level copy. Elements are NOT copied"
- (SELECTQ (TYPEP EVBOX)
- ((EVDOIT) (COPY-EVDOIT EVBOX))
- ((EVDATA) (COPY-EVDATA EVBOX))
- ((EVPORT) (COPY-EVPORT EVBOX))
- (T (FERROR "Dont' know how to copy ~A" EVBOX))))
-
- ;;; copying no longer flattens boxes down into numbers because the number-box? check
- ;;; is costing us about 2500 microseconds PER COPY (and we are copying EVERYWHERE...)
- ;;; This is as opposed to the fact that CONSing up an evbox takes about 380 microseconds
- ;;; and getting the template for some function that REALLY wants a number (not that many due
- ;;; to the existence of data-box arithmetic) like a turtle function doesn't cost us anything
- ;;; cause we got to look for it anyway
- (DEFUN SHALLOW-COPY-FOR-EVALUATOR (THING)
- (COND ((NOT (OR (EVAL-BOX? THING) (EVAL-PORT? THING))) THING) ;non-boxes
- ((OR (GRAPHICS-BOX? THING) (GRAPHICS-DATA-BOX? THING) (SPRITE-BOX? THING))
- ;; a crock to make graphics work
- THING)
- ((BOX? THING) (MAKE-TOP-LEVEL-EVBOX-FROM-BOX THING)) ;editor boxes ev boxes
- (T (COPY-EVBOX THING))))
-
- ;;; This is the same as the above Except that numbers are boxifed instead of number boxes
- ;;; being flattened out into numbers
- (DEFUN SHALLOW-COPY-FOR-ARGLIST (THING)
- (COND ((NUMBERP THING) (MAKE-EVDATA ROWS `(,(MAKE-EVROW-FROM-ENTRY THING)))) ;numbers box
- ((NOT (OR (EVAL-BOX? THING) (EVAL-PORT? THING))) THING) ;anything but boxes
- ((OR (GRAPHICS-BOX? THING) (GRAPHICS-DATA-BOX? THING) (SPRITE-BOX? THING))
- ;; a crock to make graphics work
- THING)
- ((BOX? THING) (MAKE-TOP-LEVEL-EVBOX-FROM-BOX THING)) ;editor boxes
- (T (COPY-EVBOX THING))))
-
- ;;; It is useful to set *EVALUATOR-BOX-COPYING-FUNCTION* to this for metering purposes
- (DEFUN NO-COPY (BOX)
- BOX)
-
- ;; this is the top level function to be called to get an EvBOX
-
- (DEFUN MAKE-TOP-LEVEL-EVBOX-FROM-BOX (BOX)
- (MAKE-EVBOX-FROM-BOX BOX NIL))
-
- (DEFUN MAKE-EVBOX-FROM-BOX (BOX &OPTIONAL (NAME (GET-NAME-FOR-EVBOX BOX)))
- (CHECK-BOX-ARG BOX) ;we can take this out later for speed
- (SELECTQ (TYPEP BOX)
- ((DOIT-BOX :DOIT-BOX) (MAKE-EVDOIT ROWS (MAKE-EVROWS-FROM-BOX BOX)
- BINDINGS (COPY-LOCAL-BINDINGS BOX)
- NAME NAME))
- ((DATA-BOX :DATA-BOX) (MAKE-EVDATA ROWS (MAKE-EVROWS-FROM-BOX BOX)
- BINDINGS (COPY-LOCAL-BINDINGS BOX)
- NAME NAME))
- ((PORT-BOX :PORT-BOX) (MAKE-EVPORT TARGET (TELL BOX :PORTS)
- NAME NAME))
- (OTHERWISE (FERROR "Don't know how to make an Evbox from ~A" BOX))))
-
- (DEFUN MAKE-BOX-FROM-EVBOX (EVBOX)
- (SELECTQ (TYPEP EVBOX)
- ((EVDATA EVDOIT)
- (let ((new-box (MAKE-BOX (EVBOX-ROW-ITEMS EVBOX) :DATA-BOX (EVBOX-NAME EVBOX))))
- (let ((ll (get-evbox-local-library evbox)))
- (when (not (null ll))
- (send new-box :set-local-library ll)
- (send new-box :add-static-variable-pair *exporting-box-marker* ll)
- (send ll :export-all-variables)))
- new-box))
- ((EVPORT) (PORT-TO-INTERNAL (GET-PORT-TARGET EVBOX)))))
-
-
-
- ;;;; Stream interface
-
- (DEFUN MAKE-ROW-STREAM-FROM-EVROW (EVROW)
- (MAKE-ROW-STREAM `(:ROW . ,(EVROW-ITEMS EVROW))))
-
- (DEFUN MAKE-EVDATA-STREAM (EVDATA)
- (MAKE-BOX-STREAM `(:BOX
- (:TYPE :DATA-BOX :DISPLAY-STYLE-LIST (:NORMAL NIL NIL)
- :NAME ,(EVBOX-NAME EVDATA))
- ,@(LOOP FOR ROW IN (EVBOX-ROWS EVDATA)
- COLLECT (MAKE-ROW-STREAM-FROM-EVROW ROW)))))
-
- (DEFUN MAKE-EVDOIT-STREAM (EVDATA)
- (MAKE-BOX-STREAM `(:BOX
- (:TYPE :DOIT-BOX :DISPLAY-STYLE-LIST (:NORMAL NIL NIL)
- :NAME ,(EVBOX-NAME EVDATA))
- ,@(LOOP FOR ROW IN (EVBOX-ROWS EVDATA)
- COLLECT (MAKE-ROW-STREAM-FROM-EVROW ROW)))))
-
- ;; this needs to handle targets which are evboxes (2 cases here: evbox is(not) also returned)
- (DEFUN MAKE-EVPORT-STREAM (EVPORT)
- (MAKE-BOX-STREAM (PORT-TO-INTERNAL (EVPORT-TARGET EVPORT))))
-
- (DEFPROP EVDATA MAKE-EVDATA-STREAM :MAKE-BOXER-STREAM)
- (DEFPROP EVDOIT MAKE-EVDOIT-STREAM :MAKE-BOXER-STREAM)
- (DEFPROP EVPORT MAKE-EVPORT-STREAM :MAKE-BOXER-STREAM)
-
-
- ;;; This is used to convert the result of BOXER-READ into something
- ;;; the evaluator can deal with
- (DEFUN PARSE-LIST-FOR-EVAL (LIST)
- (LOOP FOR ELEMENT IN LIST
- UNTIL (COMMENT-CHA? ELEMENT)
- UNLESS (SPACES? ELEMENT)
- COLLECT (COND ((OR (LABEL-PAIR? ELEMENT) (EVAL-IT-TOKEN? ELEMENT)
- (UNBOX-TOKEN? ELEMENT))
- ELEMENT)
- ((LISTP ELEMENT) (PARSE-LIST-FOR-EVAL ELEMENT))
- (T ELEMENT))))
-
- (DEFUN TOTALLY-DEBLANK (EVROW)
- (REM #'(LAMBDA (BLKSYM ENTRY)(AND (LISTP ENTRY)(EQ (CAR ENTRY) BLKSYM)))
- *SPACING-INFO-SYMBOL* EVROW))
- (COMPILER:MAKE-OBSOLETE TOTALLY-DEBLANK
- "You probably want to be using PARSE-LIST-FOR-EVAL instead. ")
-
- (DEFUN REMOVE-SPACES-FROM-LEFT (LIST)
- (MEM #'(LAMBDA (IGNORE X) (NOT (SPACES? X))) 'IGNORE LIST))
-
- (DEFUN LEFT-JUSTIFY (EVROW)
- (SETF (EVROW-ITEMS EVROW) (REMOVE-SPACES-FROM-LEFT (EVROW-ITEMS EVROW))))
-
- (DEFUN ADD-SPACES-TO-RIGHT (LIST SPACES)
- (APPEND LIST (NCONS (MAKE-SPACES SPACES))))
-
- ;;;; Evaluator Interface
-
- (DEFUN EVBOX-HAS-INPUTS? (EVBOX)
- (MEMQ (GET-FIRST-ELEMENT-IN-EVROW (GET-FIRST-ROW-IN-EVBOX EVBOX)) *SYMBOLS-FOR-INPUT-LINE*))
-
- (DEFUN GET-EVBOX-ROWS-FOR-EVAL (EVBOX)
- (IF (EVBOX-HAS-INPUTS? EVBOX)
- (CDR (EVBOX-ROW-ENTRIES EVBOX))
- (EVBOX-ROW-ENTRIES EVBOX)))
-
-
-
- ;;;; Getting useful info ABOUT Evboxes
-
- (DEFUN EVROW-LENGTH-IN-ELEMENTS (EVROW)
- (LENGTH (EVROW-ENTRIES EVROW)))
-
- (DEFF EV-ROW-LENGTH-IN-ELEMENTS #'EVROW-LENGTH-IN-ELEMENTS)
- (COMPILER:MAKE-OBSOLETE EV-ROW-LENGTH-IN-ELEMENTS "Use EVROW-LENGTH-IN-ELEMENTS instead. ")
-
- (DEFSUBST EVBOX-LENGTH-IN-ROWS (EVBOX)
- (LENGTH (EVBOX-ROWS EVBOX)))
-
- (DEFUN EVBOX-LENGTH-IN-ELEMENTS (EVBOX)
- (LOOP FOR ROW IN (EVBOX-ROWS EVBOX)
- SUMMING (EVROW-LENGTH-IN-ELEMENTS ROW)))
-
- (DEFUN CHA-LENGTH-OF-EVROW-ITEM (ITEM)
- (COND ((SPACES? ITEM) (GET-SPACES ITEM))
- ((OR (EVBOX? ITEM) (BOX? ITEM) (EVPORT? ITEM)) 1)
- ((NUMBERP ITEM) (STRING-LENGTH (FORMAT NIL "~A" ITEM))) ;loses on *NOPOINT (sometimes)
- ((LABEL-PAIR? ITEM) (+ (STRING-LENGTH (LABEL-PAIR-LABEL ITEM))
- (STRING-LENGTH (LABEL-PAIR-ELEMENT ITEM)) 1))
- ((UNBOX-TOKEN? ITEM) (1+ (CHA-LENGTH-OF-EVROW-ITEM (UNBOX-TOKEN-ELEMENT ITEM))))
- ((EVAL-IT-TOKEN? ITEM) (1+ (CHA-LENGTH-OF-EVROW-ITEM (EVAL-IT-TOKEN-ELEMENT ITEM))))
- (T (STRING-LENGTH ITEM))))
-
- (DEFSUBST ITEM-LIST-LENGTH-IN-CHAS (LIST)
- (LOOP FOR ITEM IN LIST SUMMING (CHA-LENGTH-OF-EVROW-ITEM ITEM)))
-
- (DEFUN EVROW-LENGTH-IN-CHAS (EVROW)
- (ITEM-LIST-LENGTH-IN-CHAS (EVROW-ITEMS EVROW)))
-
- (DEFF EV-ROW-LENGTH-IN-CHAS #'EVROW-LENGTH-IN-CHAS)
- (COMPILER:MAKE-OBSOLETE EV-ROW-LENGTH-IN-CHAS "Use EVROW-LENGTH-IN-CHAS instead. ")
-
- (DEFUN EVROWS-MAX-LENGTH-IN-CHAS (ROWS)
- (LOOP FOR ROW IN ROWS
- MAXIMIZE (EVROW-LENGTH-IN-CHAS ROW)))
-
- (DEFUN EVBOX-MAX-LENGTH-IN-CHAS (EVBOX)
- (EVROWS-MAX-LENGTH-IN-CHAS (EVBOX-ROWS EVBOX)))
-
- ;;; Stringifying
-
- (DEFSUBST MAKE-BLANK-STRING (LENGTH)
- (STRING (MAKE-ARRAY LENGTH ':TYPE 'ART-STRING :INITIAL-VALUE #\SPACE)))
-
- (DEFUN STRINGIFY (ITEM)
- (COND ((SPACES? ITEM) (MAKE-BLANK-STRING (GET-SPACES ITEM)))
- ((EVAL-BOX? ITEM) "[]")
- ((NUMBERP ITEM) (FORMAT NIL "~A" ITEM))
- ((LABEL-PAIR? ITEM)
- (FORMAT NIL "~A:~A" (LABEL-PAIR-LABEL ITEM) (LABEL-PAIR-ELEMENT ITEM)))
- ((UNBOX-TOKEN? ITEM) (FORMAT NIL "@~A" (UNBOX-TOKEN-ELEMENT ITEM)))
- ((EVAL-IT-TOKEN? ITEM) (FORMAT NIL "!~A" (EVAL-IT-TOKEN-ELEMENT ITEM)))
- ((AND (SYMBOLP ITEM) (GET ITEM 'CONVERTED-CHARACTER))
- (FORMAT NIL "~C" (GET ITEM 'CONVERTED-CHARACTER)))
- ((LISTP ITEM)
- (LET ((RETURN-STRING ""))
- (DOLIST (I ITEM)
- (SETQ RETURN-STRING (STRING-APPEND RETURN-STRING (STRINGIFY I))))
- RETURN-STRING))
- (T (STRING ITEM))))
-
- (DEFUN EVROW-TEXT-STRING (ROW)
- (LET ((RETURN-STRING ""))
- (DOLIST (ITEM (EVROW-ITEMS ROW))
- (SETQ RETURN-STRING (STRING-APPEND RETURN-STRING (STRINGIFY ITEM))))
- RETURN-STRING))
-
- (DEFUN EVBOX-TEXT-STRING (BOX)
- (DO* ((ROWS (EVBOX-ROWS BOX) (CDR ROWS))
- (ROW (CAR ROWS))
- (STRING ""))
- ((NULL ROWS) STRING)
- (SETQ STRING (STRING-APPEND STRING (EVROW-TEXT-STRING ROW)))
- (UNLESS (EQ ROW (CAR ROWS))
- (SETQ STRING (STRING-APPEND STRING (STRING #\CR))))))
-
-
-
-
- ;;;; Prebox selectors. Return NIL when the element isn't there
- ;;;; Maybe these should all be SUBSTs ??
-
- (DEFSUBST GET-NTH-ROW-IN-EVBOX (N EVBOX)
- (NTH N (EVBOX-ROWS EVBOX)))
-
- (DEFSUBST GET-FIRST-ROW-IN-EVBOX (EVBOX)
- (CAR (EVBOX-ROWS EVBOX)))
-
- (DEFSUBST GET-FIRST-ELEMENT-IN-EVROW (EVROW)
- (CAR (EVROW-ENTRIES EVROW)))
-
- (DEFSUBST GET-LAST-ELEMENT-IN-EVROW (EVROW)
- (CAR (LAST (EVROW-ENTRIES EVROW))))
-
- ;; 0 based
- (DEFUN GET-NTH-ELEMENT-IN-EVROW (N EVROW)
- (NTH N (EVROW-ENTRIES EVROW)))
-
- (DEFSUBST REMOVE-FROM-LIST (N LIST)
- (REMQ (NTH N LIST) LIST 1))
-
- ;;; These CONS up a new rows (no side effects !!!)
-
- (DEFUN GET-BUTNTH-ELEMENT-IN-EVROW (N EVROW)
- (LET* ((ENTRIES (EVROW-ENTRIES EVROW))
- (ITEM (NTH N ENTRIES)))
- (MAKE-EVROW ENTRIES (REMOVE-FROM-LIST N ENTRIES)
- ITEMS (REMQ ITEM (EVROW-ITEMS EVROW) 1))))
-
- (DEFSUBST GET-REST-ELEMENTS-IN-EVROW (EVROW)
- (LET ((ENTRIES (EVROW-ENTRIES EVROW)))
- (MAKE-EVROW ENTRIES (CDR ENTRIES)
- ITEMS (REMOVE-SPACES-FROM-LEFT
- (CDR (MEMQ (CAR ENTRIES) (EVROW-ITEMS EVROW)))))))
-
- (DEFSUBST GET-BUTLAST-ELEMENTS-IN-EVROW (EVROW)
- (LET ((ENTRIES (EVROW-ENTRIES EVROW)))
- (MAKE-EVROW ENTRIES (BUTLAST ENTRIES)
- ITEMS (REMQ (CAR (LAST ENTRIES)) (EVROW-ITEMS EVROW) 1))))
-
- (DEFUN GET-EVBOX-ELEMENTS (EVBOX)
- (LOOP FOR ROW-ENTRIES IN (EVBOX-ROW-ENTRIES EVBOX)
- APPENDING ROW-ENTRIES))
-
- ;;; EvBox mutators
-
- (DEFUN SET-NTH-ROW-IN-EVBOX (N BOX NEW-ROW)
- (LET ((ROWS (EVBOX-ROWS BOX)))
- (SETF (NTH N ROWS) NEW-ROW)))
-
- (DEFPROP GET-NTH-ROW-IN-EVBOX
- ((GET-NTH-ROW-IN-EVBOX N EVBOX) SET-NTH-ROW-IN-EVBOX N EVBOX SI:VAL) SETF)
-
- (DEFMACRO DELETE-NTH-ITEM-IN-EVROW (N EVROW)
- `(LET ((ITEM (NTH ,N (EVROW-ENTRIES ,EVROW))))
- (SPLICE-ITEM-OUT-OF-LIST (EVROW-ENTRIES ,EVROW) ITEM)
- (SPLICE-ITEM-OUT-OF-LIST (EVROW-ITEMS ,EVROW) ITEM)))
-
- (DEFMACRO INSERT-NTH-ITEM-IN-EVROW (N EVROW NEW-ITEM)
- `(PROGN
- (SPLICE-ITEM-INTO-LIST-AT (EVROW-ENTRIES ,EVROW) ,NEW-ITEM ,N)
- (SPLICE-ITEM-INTO-LIST-AT (EVROW-ITEMS ,EVROW) ,NEW-ITEM
- (OR (FIND-POSITION-IN-LIST (NTH ,N (EVROW-ENTRIES ,EVROW))
- (EVROW-ITEMS ,EVROW))
- (LENGTH (EVROW-ITEMS ,EVROW))))))
-
- (DEFMACRO CHANGE-NTH-ITEM-IN-EVROW (N EVROW NEW-ITEM)
- `(LET ((ITEM (NTH ,N (EVROW-ENTRIES ,EVROW))))
- (SPLICE-ITEM-INTO-LIST (EVROW-ENTRIES ,EVROW) ,NEW-ITEM ITEM)
- (SPLICE-ITEM-OUT-OF-LIST (EVROW-ENTRIES ,EVROW) ITEM)
- (SPLICE-ITEM-INTO-LIST (EVROW-ITEMS ,EVROW) ,NEW-ITEM ITEM)
- (SPLICE-ITEM-OUT-OF-LIST (EVROW-ITEMS ,EVROW) ITEM)))
-
- ;; CONSes up a new row, does NOT side effect
- (DEFF REMOVE-NTH-ITEM-IN-EVROW #'GET-BUTNTH-ELEMENT-IN-EVROW)
-
- ;;;; Genericism...
-
- ;;; Predicates
-
- (DEFSUBST EVAL-NAMED? (THING)
- (OR (AND (BOX? THING) (NAME-ROW? (TELL THING :NAME-ROW)))
- (AND (OR (EVBOX? THING) (EVPORT? THING)) (NOT-NULL (EVBOX-NAME THING)))))
-
- (DEFUN EVAL-EMPTY? (BOX)
- (NOT (DOLIST (ROW (GET-BOX-ROWS BOX)) (UNLESS (NULL ROW) (RETURN T)))))
-
- (DEFSUBST NUMBER-BOX? (BOX)
- (AND (= 1 (GET-BOX-LENGTH-IN-ELEMENTS BOX)) (NUMBERP (GET-FIRST-ELEMENT BOX))))
-
- (DEFUN NUMBERIZE (THING)
- (COND ((NUMBERP THING) THING)
- ((NUMBER-BOX? THING) (GET-FIRST-ELEMENT THING))
- (T (FERROR "Can't convert ~A into a number. " THING))))
-
- (DEFUN ELEMENT-EQUAL? (E1 E2)
- (cond ((EQ (TOKEN-TYPE (ROW-ENTRY-ELEMENT E1)) (TOKEN-TYPE (ROW-ENTRY-ELEMENT E2)))
- (COND ((EVAL-BOX? E1) (BOX-EQUAL? E1 E2))
- ((NUMBERP E1) (= E1 E2))
- (T (EQUAL E1 E2))))
- ;; try and do the right thing for random lossage
- ;; right now, this can arise from the CHARACTERS function which
- ;; returns elements as strings in order to preserve CASE
- ((and (eq (token-type e1) 'string)
- (eq (token-type e2) 'symbol))
- (string= e1 (string e2)))
- ((and (eq (token-type e2) 'string)
- (eq (token-type e1) 'symbol))
- (string= (string e1) e2))
- (t nil)))
-
- (DEFUN ROW-EQUAL? (ROW1 ROW2)
- (AND (= (LENGTH ROW1) (LENGTH ROW2))
- (NOT (LOOP FOR E1 IN ROW1
- FOR E2 IN ROW2
- UNLESS (ELEMENT-EQUAL? E1 E2)
- RETURN T))))
-
- (DEFUN BOX-EQUAL? (BOX1 BOX2)
- (LET ((ROWS1 (GET-BOX-ROWS BOX1))
- (ROWS2 (GET-BOX-ROWS BOX2)))
- (AND (= (LENGTH ROWS1) (LENGTH ROWS2))
- (NOT (LOOP FOR ROW1 IN ROWS1
- FOR ROW2 IN ROWS2
- UNLESS (ROW-EQUAL? ROW1 ROW2)
- RETURN T)))))
-
- ;; Useful info
- (DEFUN GET-BOX-LENGTH-IN-ROWS (BOX-OR-PORT)
- (LET ((BOX (BOX-OR-PORT-TARGET BOX-OR-PORT)))
- (COND ((port-box? box) (tell (tell box :ports) :length-in-rows))
- ((BOX? BOX) (TELL BOX :LENGTH-IN-ROWS))
- ((NUMBERP BOX) 1)
- (T (EVBOX-LENGTH-IN-ROWS BOX)))))
-
- (DEFUN GET-BOX-LENGTH-IN-ELEMENTS (BOX-OR-PORT)
- (LET ((BOX (BOX-OR-PORT-TARGET BOX-OR-PORT)))
- (COND ((BOX? BOX) (LENGTH (TELL BOX :ELEMENTS)))
- ((NUMBERP BOX) 1)
- (T (EVBOX-LENGTH-IN-ELEMENTS BOX)))))
-
- ;; Stringiness and stringosity
-
- (DEFUN ROW-STRING (ROW)
- (COND ((ROW? ROW) (TELL ROW :TEXT-STRING))
- ((EVROW? ROW) (EVROW-TEXT-STRING ROW))
- (T (FERROR "Can't coerce ~A into a string" ROW))))
-
- (DEFUN TEXT-STRING (BOX-OR-PORT)
- (LET ((BOX (BOX-OR-PORT-TARGET BOX-OR-PORT)))
- (COND ((EVBOX? BOX) (EVBOX-TEXT-STRING BOX))
- ((NUMBERP BOX) (FORMAT NIL "~A" BOX))
- ((BOX? BOX) (TELL BOX :TEXT-STRING))
- (T (FERROR "DOn't know how to make a string from ~A" BOX)))))
-
- ;; accessors for inner structure
-
- (DEFUN GET-BOX-ROWS (BOX-OR-PORT &OPTIONAL (SPACES? NIL))
- "Returns a list of rows which appear as a list of tokens"
- (LET ((BOX (BOX-OR-PORT-TARGET BOX-OR-PORT)))
- (COND ((AND SPACES? (BOX? BOX))
- (MAP-TELL (TELL BOX :ROWS) :ITEMS))
- ((BOX? BOX)
- (MAP-TELL (TELL BOX :ROWS) :ENTRIES))
- ((NUMBERP BOX)
- (NCONS (NCONS BOX)))
- ((NULL SPACES?)
- (EVBOX-ROW-ENTRIES BOX))
- (T (EVBOX-ROW-ITEMS BOX)))))
-
-
- (DEFUN GET-NTH-ROW (N BOX-OR-PORT &OPTIONAL (SPACES? NIL))
- (LET ((BOX (BOX-OR-PORT-TARGET BOX-OR-PORT)))
- (COND ((AND (NULL SPACES?) (BOX? BOX))
- (TELL-CHECK-NIL (TELL BOX :ROW-AT-ROW-NO N) :ENTRIES))
- ((BOX? BOX)
- (TELL-CHECK-NIL (TELL BOX :ROW-AT-ROW-NO N) :ITEMS))
- ((AND (NUMBERP BOX) (= 0 N)) (NCONS BOX))
- ((NULL SPACES?)
- (EVROW-ENTRIES (GET-NTH-ROW-IN-EVBOX N BOX)))
- (T (EVROW-ITEMS (GET-NTH-ROW-IN-EVBOX N BOX))))))
-
- (DEFUN GET-FIRST-ROW (BOX-OR-PORT &OPTIONAL (SPACES? NIL))
- (LET ((BOX (BOX-OR-PORT-TARGET BOX-OR-PORT)))
- (COND ((AND (NULL SPACES?) (BOX? BOX))
- (TELL (TELL BOX :FIRST-INFERIOR-ROW) :ENTRIES))
- ((BOX? BOX)
- (TELL (TELL BOX :FIRST-INFERIOR-ROW) :ITEMS))
- ((NUMBERP BOX) (NCONS BOX))
- ((NULL SPACES?)
- (EVROW-ENTRIES (GET-FIRST-ROW-IN-EVBOX BOX)))
- (T (EVROW-ITEMS (GET-FIRST-ROW-IN-EVBOX BOX))))))
-
- (DEFUN GET-FIRST-ELEMENT (BOX)
- (IF (NUMBERP BOX) BOX
- (DOTIMES (I (GET-BOX-LENGTH-IN-ROWS BOX))
- (LET ((ENTRIES (GET-NTH-ROW I BOX)))
- (WHEN (NOT (NULL ENTRIES)) (RETURN (CAR ENTRIES)))))))
-
- (DEFUN GET-BOX-ELEMENTS (BOX)
- (COND ((BOX? BOX) (TELL BOX :ELEMENTS))
- (T (GET-EVBOX-ELEMENTS BOX))))
-
- ;;; This port does not create back-pointers to the port so that the ports can be GC'd after
- ;;; the evaluation returns
-
- (DEFUN PORT-TO-FOR-EVAL (TARGET &optional name-too)
- (LET ((PORT (MAKE-INITIALIZED-BOX :TYPE 'PORT-BOX)))
- (TELL PORT :SET-PORT-TO-BOX-FOR-EVAL TARGET)
- (when (and name-too (not (null (box-name target))))
- (tell port :set-name (make-name-row (list (box-name target)))))
- PORT))
-
- ;; this should make Evports but STREAMS have to be fixed to handled EvBoxes first...
- (DEFSUBST PORT-TO-INFERIORS-IN-LIST (LIST &optional name-too)
- (MAPCAR #'(LAMBDA (X) (IF (EVAL-BOX? X) (PORT-TO-FOR-EVAL X name-too) X)) LIST))
-
- (DEFUN PORT-TO-INFERIORS (EVROW)
- "Makes an EVROW which replaces every BOX in the arg with a PORT to that BOX."
- (MAKE-EVROW-FROM-ITEMS (PORT-TO-INFERIORS-IN-LIST (EVROW-ITEMS EVROW))))
-
- ;;; mutators
-
- ;; for ROWS (delete, insert and change)
- ;0 based
- (DEFUN DELETE-ROW-AT-ROW-NO (N BOX &OPTIONAL (NEW? NIL))
- (COND ((NOT-NULL NEW?)
- (LET ((ROWS (GET-BOX-ROWS BOX)))
- (MAKE-EVDATA ROWS (APPEND (mapcar #'make-evrow-from-items (FIRSTN N ROWS))
- (mapcar #'make-evrow-from-items (NTHCDR (1+ N) ROWS))))))
- ((BOX? BOX) (TELL BOX :DELETE-ROW-AT-ROW-NO N)
- (TELL BOX :MODIFIED)
- ':NOPRINT)
- (T (SETF (EVBOX-ROWS BOX) (APPEND (FIRSTN N (EVBOX-ROWS BOX))
- (NTHCDR (1+ N) (EVBOX-ROWS BOX))))
- ':NOPRINT)))
-
- (DEFUN INSERT-ROW-AT-ROW-NO (N BOX NEW-ROW &OPTIONAL (NEW? NIL))
- (COND ((NOT-NULL NEW?)
- (LET ((ROWS (GET-BOX-ROWS BOX)))
- (MAKE-EVDATA ROWS (APPEND (mapcar #'make-evrow-from-items (FIRSTN N ROWS))
- (NCONS NEW-ROW)
- (mapcar #'make-evrow-from-items (NTHCDR N ROWS))))))
- ((BOX? BOX)
- (TELL BOX :INSERT-ROW-AT-ROW-NO (MAKE-ROW (evrow-items NEW-ROW)) N)
- (TELL BOX :MODIFIED)
- ':NOPRINT)
- (T (SETF (EVBOX-ROWS BOX)
- (APPEND (FIRSTN N (EVBOX-ROWS BOX))
- (NCONS NEW-ROW)
- (NTHCDR N (EVBOX-ROWS BOX))))
- ':NOPRINT)))
-
- (DEFUN CHANGE-ROW-AT-ROW-NO (N BOX NEW-ROW &OPTIONAL (NEW? NIL))
- (COND ((NOT-NULL NEW?)
- (LET ((ROWS (GET-BOX-ROWS BOX)))
- (MAKE-EVDATA ROWS (APPEND (mapcar #'make-evrow-from-items (FIRSTN N ROWS))
- (NCONS NEW-ROW)
- (mapcar #'make-evrow-from-items (NTHCDR (1+ N) ROWS))))))
- ((BOX? BOX)
- (TELL BOX :DELETE-ROW-AT-ROW-NO N)
- (TELL BOX :INSERT-ROW-AT-ROW-NO (MAKE-ROW (evrow-items NEW-ROW)) N)
- (TELL BOX :MODIFIED)
- ':NOPRINT)
- (T (SETF (EVBOX-ROWS BOX)
- (APPEND (FIRSTN N (EVBOX-ROWS BOX))
- (NCONS NEW-ROW)
- (NTHCDR (1+ N) (EVBOX-ROWS BOX))))
- ':NOPRINT)))
-
- ;;; Useful interactions between character level and entry level representation
- ;;; these SIDE EFFECT
-
- ;;; 0 based
-
- ;; Since we lose some character information after READing (for example in a LABEL PAIR), we
- ;; will sometimes need to look directly at the row on a character by character basis
- ;; these don't as yet handle nesting of compound items accurately e.g. (LABEL-PAIR (UNBOX...))
-
- (DEFSUBST COMPOUND-ENTRY? (ENTRY)
- "Returns T if the entry is allowed to have spaces within its visual representation. "
- (OR (LABEL-PAIR? ENTRY) (UNBOX-TOKEN? ENTRY) (EVAL-IT-TOKEN? ENTRY)))
-
- (DEFSUBST EXAMINE-ROW-CHARACTERS? (ENTRY)
- "Returns T if the row entry's length cannot be determined from the entry itself. "
- (OR (COMPOUND-ENTRY? ENTRY) ; spaces within the pair are lost
- (FIXP ENTRY))) ; *NOPOINT lossage
-
- (DEFSUBST COMPOUND-ENTRY-PROLOGUE-LENGTH (ENTRY)
- (COND ((LABEL-PAIR? ENTRY) (CHA-LENGTH-OF-EVROW-ITEM (LABEL-PAIR-LABEL ENTRY)))
- ;; assume that it is either an UNBOX or EVAL-IT token
- (T 1)))
-
- (DEFSUBST COMPOUND-ENTRY-EPILOGUE-LENGTH (ENTRY)
- (COND ((LABEL-PAIR? ENTRY) (CHA-LENGTH-OF-EVROW-ITEM (LABEL-PAIR-ELEMENT ENTRY)))
- ((UNBOX-TOKEN? ENTRY) (CHA-LENGTH-OF-EVROW-ITEM (UNBOX-TOKEN-ELEMENT ENTRY)))
- ((EVAL-IT-TOKEN? ENTRY) (CHA-LENGTH-OF-EVROW-ITEM (EVAL-IT-TOKEN-ELEMENT ENTRY)))))
-
- (DEFSUBST COMPOUND-ENTRY-INTERVENING-LENGTH (MID-NO ROW IGNORE-CHAS)
- (LOOP FOR CHA-NO = MID-NO THEN (1+ CHA-NO)
- FOR CHA = (CHA-CODE (TELL ROW :CHA-AT-CHA-NO CHA-NO))
- UNTIL (NOT (MEMBER CHA IGNORE-CHAS))
- SUMMING 1))
-
- (DEFSUBST COMPOUND-ENTRY-LENGTH (START-NO ROW ENTRY)
- (LET ((PROLOGUE-LENGTH (COMPOUND-ENTRY-PROLOGUE-LENGTH ENTRY)))
- (+ PROLOGUE-LENGTH
- (COMPOUND-ENTRY-INTERVENING-LENGTH (+ START-NO PROLOGUE-LENGTH)
- ROW
- (IF (LABEL-PAIR? ENTRY) '(#\SPACE #\:) '(#\SPACE)))
- (COMPOUND-ENTRY-EPILOGUE-LENGTH ENTRY))))
-
- (DEFSUBST ACTUAL-CHA-LENGTH-OF-ENTRY (START-NO ROW ENTRY)
- (IF (COMPOUND-ENTRY? ENTRY)
- (COMPOUND-ENTRY-LENGTH START-NO ROW ENTRY)
- (LOOP FOR CHA-NO = START-NO THEN (1+ CHA-NO)
- FOR CHA = (TELL ROW :CHA-AT-CHA-NO CHA-NO)
- UNTIL (EQUAL CHA #\SPACE)
- SUMMING 1)))
-
- (DEFUN GET-CHA-NOS-OF-ENTRY (ROW ENTRY-NO)
- "Returns 2 values corresponding to the start and stop CHA-NO of the entry. "
- (LOOP WITH ENTRY-INDEX = 0
- WITH CHA-NO = 0
- FOR ENTRY IN (TELL ROW :EVROW)
- WHEN (AND (NOT (SPACES? ENTRY)) (= ENTRY-NO ENTRY-INDEX))
- RETURN (VALUES CHA-NO (+ CHA-NO (IF (EXAMINE-ROW-CHARACTERS? ENTRY)
- (ACTUAL-CHA-LENGTH-OF-ENTRY CHA-NO ROW ENTRY)
- (CHA-LENGTH-OF-EVROW-ITEM ENTRY))))
- UNLESS (SPACES? ENTRY)
- DO (INCF ENTRY-INDEX)
- DO (INCF CHA-NO (IF (EXAMINE-ROW-CHARACTERS? ENTRY)
- (ACTUAL-CHA-LENGTH-OF-ENTRY CHA-NO ROW ENTRY)
- (CHA-LENGTH-OF-EVROW-ITEM ENTRY)))
- FINALLY
- (FERROR "There are less than ~D entries in ~A" ENTRY-NO ROW)))
-
- (DEFUN MAKE-ROW-WITH-PADDED-VALUE (THING &OPTIONAL (PAD-LEFT NIL) (PAD-RIGHT T))
- (LET ((ROW (MAKE-ROW `(,THING))))
- (WHEN PAD-LEFT (TELL ROW :INSERT-CHA-AT-CHA-NO #\SPACE 0))
- (WHEN PAD-RIGHT (TELL ROW :APPEND-CHA #\SPACE))
- ROW))
-
- ;;; Row mutators for
-
- (DEFUN DELETE-ENTRY-IN-ROW-AT-ENTRY-NO (ROW ENTRY-NO)
- (MULTIPLE-VALUE-BIND (START-CHA-NO STOP-CHA-NO)
- (GET-CHA-NOS-OF-ENTRY ROW ENTRY-NO)
- (TELL ROW :DELETE-CHAS-BETWEEN-CHA-NOS START-CHA-NO STOP-CHA-NO)))
-
- (DEFUN INSERT-ENTRY-IN-ROW-AT-ENTRY-NO (ROW ENTRY-NO NEW-ENTRY)
- (IF ( ENTRY-NO (LENGTH (TELL ROW :ENTRIES)))
- (TELL ROW :INSERT-ROW-CHAS-AT-CHA-NO (MAKE-ROW-WITH-PADDED-VALUE NEW-ENTRY T)
- (TELL ROW :LENGTH-IN-CHAS))
- (TELL ROW :INSERT-ROW-CHAS-AT-CHA-NO (MAKE-ROW-WITH-PADDED-VALUE NEW-ENTRY)
- (GET-CHA-NOS-OF-ENTRY ROW ENTRY-NO))))
-
- (DEFUN CHANGE-ENTRY-IN-ROW-AT-ENTRY-NO (ROW ENTRY-NO NEW-ENTRY)
- (LET ((NEW-ROW (MAKE-ROW-WITH-PADDED-VALUE NEW-ENTRY)))
- (MULTIPLE-VALUE-BIND (START-CHA-NO STOP-CHA-NO)
- (GET-CHA-NOS-OF-ENTRY ROW ENTRY-NO)
- (TELL ROW :DELETE-CHAS-BETWEEN-CHA-NOS START-CHA-NO STOP-CHA-NO)
- (TELL ROW :INSERT-ROW-CHAS-AT-CHA-NO NEW-ROW START-CHA-NO))))
-
- ;;; The actual mutators which other functions can call
- ;;; No bounds checking
-
- (DEFUN DELETE-ITEM-AT-ITEM-NO-IN-ROW-NO (I R BOX &OPTIONAL (NEW? NIL))
- (COND ((NOT-NULL NEW?)
- (LET* ((ROWS (GET-BOX-ROWS BOX))
- (row (get-nth-row r box)))
- (MAKE-EVDATA-FROM-ROWS (APPEND (FIRSTN R ROWS)
- (NCONS (append (firstn i row) (nthcdr (1+ i) row)))
- (NTHCDR (1+ R) ROWS)))))
- ((BOX? BOX)
- (DELETE-ENTRY-IN-ROW-AT-ENTRY-NO (TELL BOX :ROW-AT-ROW-NO R) I)
- ':NOPRINT)
- (T (DELETE-NTH-ITEM-IN-EVROW I (GET-NTH-ROW-IN-EVBOX R BOX))
- ':NOPRINT)))
-
- (DEFUN INSERT-ITEM-AT-ITEM-NO-IN-ROW-NO (I R BOX NEW-ITEM &OPTIONAL (NEW? NIL))
- (COND ((NOT-NULL NEW?)
- (LET* ((ROWS (GET-BOX-ROWS BOX))
- (ROW (GET-NTH-ROW R BOX)))
- (MAKE-EVDATA-FROM-ROWS (APPEND (FIRSTN R ROWS)
- (NCONS (APPEND (FIRSTN I ROW) (NCONS NEW-ITEM)
- (NTHCDR I ROW)))
- (NTHCDR (1+ R) ROWS)))))
- ((BOX? BOX)
- (INSERT-ENTRY-IN-ROW-AT-ENTRY-NO (TELL BOX :ROW-AT-ROW-NO R) I NEW-ITEM)
- ':NOPRINT)
- (T (INSERT-NTH-ITEM-IN-EVROW I (GET-NTH-ROW-IN-EVBOX R BOX) NEW-ITEM)
- ':NOPRINT)))
-
- (DEFUN CHANGE-ITEM-AT-ITEM-NO-IN-ROW-NO (I R BOX NEW-ITEM &OPTIONAL (NEW? NIL))
- (COND ((NOT-NULL NEW?)
- (LET* ((ROWS (GET-BOX-ROWS BOX))
- (ROW (GET-NTH-ROW R BOX)))
- (MAKE-EVDATA-FROM-ROWS (APPEND (FIRSTN R ROWS)
- (NCONS (APPEND (FIRSTN I ROW) (NCONS NEW-ITEM)
- (NTHCDR (1+ I) ROW)))
- (NTHCDR (1+ R) ROWS)))))
- ((BOX? BOX)
- (CHANGE-ENTRY-IN-ROW-AT-ENTRY-NO (TELL BOX :ROW-AT-ROW-NO R) I NEW-ITEM)
- ':NOPRINT)
- (T (CHANGE-NTH-ITEM-IN-EVROW I (GET-NTH-ROW-IN-EVBOX R BOX) NEW-ITEM)
- ':NOPRINT)))
-
- (DEFUN GET-ROW-AND-COL-NUMBER (N BOX)
- "Converts 1-based GET-NTH coordinates into 0-based GET-RC coordinates. Values returned are row number and column number"
- (DECLARE (VALUES ROW-NO INDEX))
- (LOOP WITH INDEX = (1- N)
- FOR ROW IN (GET-BOX-ROWS BOX)
- FOR ROW-NO = 0 THEN (1+ ROW-NO)
- FOR LENGTH = (LENGTH ROW)
- WHEN (< INDEX LENGTH)
- RETURN (VALUES ROW-NO INDEX)
- DO (SETQ INDEX (- INDEX LENGTH))))
-
- ;;; gets the whitespace out (you try scrubbing them out....)
- (DEFUN TRIM-EMPTY-ROWS (LIST-OF-ROWS)
- (LOOP FOR ROW IN LIST-OF-ROWS
- UNLESS (NULL (SUBSET-NOT #'SPACES? (EVROW-ITEMS ROW)))
- COLLECT ROW INTO NEW-ROWS
- FINALLY
- (RETURN (IF (NULL NEW-ROWS) `(,(MAKE-EMPTY-EVROW)) NEW-ROWS))))
-